View.php

<?php

namespace Fresh;

class View extends ViewRoot {

    public function initialize(){
        $this->addQuery('//*[@rb-table]',[$this,'handleEntity']);
        $this->addCompileHandler('entity-prop',[$this,'handleEntityProp']);
        $this->setRuntimeHandler('formatObjectValue',[$this,'formatObjectValue']);
        // $this->addRuntimeHandler('find',[$this,'find']);
        $this->addFormatter('markdown',[$this,'mdToHtml']);
        // $this->addFormatter('imageSrc',[$this,'mdToHtml']);
        // $this->addRuntimeHandler('format_markdown',[$this,'mdToHtml']);

        $this->addQuery('//*[@tf-format]',[$this,'formatNode']);
        $this->addRuntimeHandler('formatRawValue',[$this,'formatRawValue']);
    }

    public function formatNode(\Taeluf\PHTML $doc, \Fresh\View $view, \Taeluf\PHTML\Compiler $compiler, \Taeluf\PHTML\Node $node){
        
        $format = $node->getAttribute('tf-format');
        $node->removeAttribute('tf-format');
        $ob = $compiler->placeholderFor('<?php ob_start(); ?>');
        $ih = $node->innerHTML;
        $convert = $compiler->placeholderFor('<?php echo $this->callHandler(\'formatRawValue\',ob_get_clean(),\''.$format.'\')[0]; ?>');
        
        $node->innerHTML = $ob . $ih . $convert;
    }

    public function formatRawValue($value,$formatter){
        if ($formatter=='')return $value;
        $method = 'format_'.$formatter;
        $ret = $this->callHandler($method,$value);
        // print_r($ret);
        // exit;
        return $ret;
    }

    public function getEntities(){
        $viewContent = file_get_contents($this->file);
        // echo $viewContent."\n\n";
        $compiler = new \Taeluf\PHTML\Compiler();
        $cleanSource = $compiler->cleanSource($viewContent);
        $doc = new \Taeluf\PHTML($cleanSource);

        $entities = $doc->xpath('//*[@rb-table]');
        
        return $entities;
    }

    public function mdToHtml($markdown){
        $converter = new \League\CommonMark\CommonMarkConverter([
            // 'html_input' => 'strip',
            'allow_unsafe_links' => false,
        ]);
        $newValue = $converter->convertToHtml($markdown);
        return $newValue;
    }

    public function formatObjectValue($object,$param,$formatter){

        // $handler = $this->runtimeHandlers['format_'.$formatter] ?? null;
        $value = $object->$param;
        if ($formatter=='')return $value;
        $method = 'format_'.$formatter;
        // echo "\n\n\n\n".$method;
        // exit;
        // $list = $this->handler->runtime->$method;
        // echo 'na na na';
        // var_dump($list);
        // exit;

        // echo $method;
        // exit;
        // $ret = $this->handler->callMethod('runtime',$method,[$value]);
        $ret = $this->callHandler($method,$value);

        return $ret;
        // $this->format
        // if (is_callable($handler))$value = $handler($value);
        // return $value;
    }
    protected function handleEntityProp($compiler,$propNode,$entityInfo){



        $varName = $entityInfo['table'];

        $propName = $propNode->getAttribute('rb-prop');
        $format = $propNode->getAttribute('rb-format');

        $propNode->removeAttribute('rb-prop');
        $propNode->removeAttribute('rb-format');
        
        $tag = strtolower($propNode->tagName);
        if ($tag=='img'){
            // $format = '';
            $modAttribute = 'src';
        } else if ($tag=='a'){
            $modAttribute = 'href';
        } else {
            $modAttribute = 'textContent';
        }

        $placeholder = $compiler->placeholderFor('<?php echo $this->callHandler(\'formatObjectValue\',$'.$varName.',\''.$propName.'\',\''.$format.'\'); ?>');
        
        $propNode->$modAttribute = $placeholder;

    }

    protected function handleEntity(\Taeluf\PHTML $doc, \Fresh\View $view, \Taeluf\PHTML\Compiler $compiler, \Taeluf\PHTML\Node $entity){

        //process the entity
        // create a lookup
        // replace the entity node with a code placeholder
        // Set the replacement text to the fully-processed version of the entity
        // but use an array, which will later be imploded
        // this way, objects can be in the array & not be __toString'd until everything is complete

        //
        // $entity->outerHTML = "a_code_placeholder";
        // $compiler->php['a_code_placeholder'] =
            // [
                // $prependedPHPCode,
                // $lookupCode,
                // $entity, // this will __toString at the last possible moment
                // $closeTheLoopCode,
                // $appendedPHPCode
            // ];
        // $viewHtml = $entity;
        // echo 'zee';exit;
        $placeholder = $compiler->placeholderFor($entity);

        $entity->parentNode->replaceChild($doc->createTextNode($placeholder),$entity);
        

        $rbAttrs = [];
        foreach ($entity->attributes() as $attr){
            if (strtolower(substr($attr->name,0,3))=='rb-'){
                $entity->removeAttributeNode($attr);
                $rbAttrs[substr($attr->name,3)] = $doc->fillWithPHP($attr->value);
            }
        }
        $varName = $rbAttrs['table'];
        $xp = new \DOMXpath($doc);
        $props = $xp->query(".//*[@rb-prop]",$entity);
        
        foreach ($props as $propNode){
            $this->executeCompileHandlers('entity-prop',$compiler,$propNode,$rbAttrs);
        }

        $phpOutput = '<?php ';
        $query = [];
        foreach ($rbAttrs as $var=>$value){
            $line = '';
            $line = 'ob_start();?>'.$value.'<?php $'.$var.' = ob_get_clean();'."\n";
            $phpOutput .= $line;

            if ($var=='table'){
                $query = "\$list = \$this->callHandler('find',\$table,\$find);";
                $queryParam = $value;
            }
        }
        $phpOutput .= ' ?>';
        $phpOutput .= "\n<?php\n".$query."\n?>\n";
        $phpOutput .= "<?php\nforeach(\$list as \$rb_object) { \${$queryParam} = \$rb_object;";
            
            /**
             * Call `$compo->addCompileHandler('View.EntityLoop.Start', $callable)`  
             * `$callable` should:
             * - Accept NO paramaters
             * - Return a string of valid PHP code
             *    - DO NOT include open & close tags @ beginning and end of your code.
             *       - You MAY close & re-open amidst your code.
             * 
             * @TODO Maybe pass some paramaters to the callable???
             * 
             * @export(Handler.Compile.View_Entity_Loop_Start)
             */
            $loopStartCode = $this->executeCompileHandlers('View.EntityLoop.Start');
            $freshCodes = implode("\n",$loopStartCode);
            $phpOutput .= $freshCodes;

        $phpOutput .= "\n?>";
        // $phpOutput .= $doc->output();
        $compiler->placeholderPrepend($placeholder,$phpOutput);
        $compiler->placeholderAppend($placeholder,
                "<?php \n} ?>\n"
            );

    }
}